module BoxFormBuilder

	# BoxFormBuilder extends FormBuilder with various methods that can be
	# used to create "boxy" forms.
	class ActionView::Helpers::FormBuilder
		# include its parent module so we can get access to box_row from within
		# a form builder
		include BoxFormBuilder
		def fields(*fields)
			html = ''

			# # Doesn't quite work
			# if [fields].flatten[0] == :all
			# 	model_name = self.instance_variable_get('@object_name').to_s
			# 	fields = model_name.to_s.camelcase.constantize.all_fields
			# end
		
			fields.flatten.each do |field_name|
				html += box_field(field_name)
			end
		
			return html
		end
	
		def get_field_data(model, field_name)
			fields = model.to_s.camelcase.constantize.field_data
			field = fields[field_name.to_sym]
		end
	
		# A box form can be used to build out a form for a model	
		def box_field(field_name)
			model_name = self.instance_variable_get('@object_name').to_s

			field = get_field_data(model_name, field_name)

			# if show is nil, then don't bother to show
			return '' if field[:show] == nil
			
			field_type = field[:show].to_sym
			label = field[:label]
			if field_type == :select
				form_html = self.send(field_type, field_name.to_s, field[:options], :class => field_type.to_s.gsub(/_/, ''))
			else
				form_html = self.send(field_type, field_name.to_s, :class => field_type.to_s.gsub(/_/, ''))				
			end

			# Tack notes below the form field
			if field[:notes]
				form_html += '<div class="notes">' + field[:notes] + '</div>'
			end
			
			if label == nil
				return form_html
			else
				return box_row(label, form_html)
			end
		end
	end

	
	def box_row(name, value='', &block)
		if (!value || value == '') && !block_given?
			# Value is not set, so we can get rid of this
			return ''
		end

		value = capture(&block) if block_given?

		html = []
		if name == nil
			html << '<div class="field">' << value << '</div>'
		else
			html << '<div class="field clearfix"><div class="left">' << name << '</div><div class="right">' << value << '</div></div>'
		end
	
		if block_given?
			concat(html.join(''), block.binding)
		else
			return html.join('')
		end
	end


	# The box_form_for method does the same thing as form_for, except that
	# it passes a "boxy" FormBuilder to the block.  It also can take a :fields
	# option which will display any field names in a "boxy" style, and a :submit
	# option, which can specify the text of a block object.  Also, box_form_for
	# will automatically add the error_messages_for methods data.
	#
	# box_form_for can be used in the following two ways:
	#
	#  <%= box_form_for(:member, :url => members_path, :fields => [:name, :email, :password], :submit => 'Signup') %>
	#
	# or a more compliacted example using blocks
	#  <% box_form_for(:member, :url => members_path, :submit => 'Signup') do |f| %>
	#	   <%= f.fields(:name, :email, :password) %>
	#	   <% box_row('Privacy') do %>
	#      <%= render :partial => 'privacy_edit', :locals => {:f => f} %>
	#    <% end %>
	#    <%= f.fields(:about_me) %>
	#  <% end %>
	
	def form_for(record_or_name_or_array, *args, &block)
		if block_given?
			_erbout = eval('_erbout', block)
		else
			_erbout = ''
		end
		
		case record_or_name_or_array
		when String, Symbol
			model = record_or_name_or_array
		when Array
			model = record_or_name_or_array.last.class.to_s
		else
			model = record_or_name_or_array.class.to_s
		end
		
		model = model.to_sym
		
		options = args[0] || {}


		# Error Messages
		_erbout << error_messages_for(model)
		
		# call parent form_for
		super(record_or_name_or_array, *args) do |f|
		
			# Specified Fields			
			_erbout << f.fields(options[:fields]) if options[:fields]
		
			# Call block if specified
			if block_given?
				_erbout << capture(f, &block)
			end
		
			# Submit Button (if specified)
			_erbout << ('<div>' + submit_tag(options[:submit], :class => 'inputsubmit') + '</div>') if options[:submit]
		end
		
		unless block_given?
			return _erbout
		end
	end
	
end